<template>
  <div
      class="workflow-node"
      :class="{ 'selected': isSelected, 'connection-hover': isConnectionHovering }"
      :style="{
      left: `${props.node.position.x}px`,
      top: `${props.node.position.y}px`,
      borderColor: nodeTypeConfig?.color || '#409EFF'
    }"
      @mousedown.stop="startDrag"
      @click.stop="selectNode"
      @contextmenu.prevent="showContextMenu"
      :data-node-id="props.node.id"
  >
    <!-- 节点头部 -->
    <div class="node-header" :style="{
      backgroundImage: `linear-gradient(90deg, ${nodeTypeConfig?.color || '#409EFF'}, #66b1ff)`
    }">
      <component v-if="nodeTypeConfig?.icon" :is="nodeTypeConfig.icon" class="node-icon"/>
      <span class="node-label">{{ props.node.label }}</span>
    </div>

    <!-- 节点内容区 -->
    <div class="node-content">
      <div class="node-description" v-if="nodeTypeConfig?.description">
        {{ nodeTypeConfig.description }}
      </div>
    </div>

    <!-- 输入锚点 -->
    <div
        v-if="(isSelected || isConnectionHovering) && props.node.inputs?.length"
        class="anchor-points left-anchors"
    >
      <div
          v-for="(port, index) in props.node.inputs"
          :key="port.id"
          class="anchor-point"
          :style="{ top: `${getPortPosition(index, props.node.inputs.length)}%` }"
          :data-node-id="props.node.id"
          :data-port-id="port.id"
          @mousedown.stop="startConnection(port.id, true, $event)"
      >
        <div class="anchor-dot"></div>
        <div class="anchor-tooltip">{{ port.name }}</div>
      </div>
    </div>

    <!-- 输出锚点 -->
    <div
        v-if="(isSelected || isConnectionHovering) && props.node.outputs?.length"
        class="anchor-points right-anchors"
    >
      <div
          v-for="(port, index) in props.node.outputs"
          :key="port.id"
          class="anchor-point"
          :style="{ top: `${getPortPosition(index, props.node.outputs.length)}%` }"
          :data-node-id="props.node.id"
          :data-port-id="port.id"
          @mousedown.stop="startConnection(port.id, false, $event)"
      >
        <div class="anchor-dot"></div>
        <div class="anchor-tooltip">{{ port.name }}</div>
      </div>
    </div>

    <!-- 右键菜单 -->
    <div
        v-if="showMenu"
        class="node-context-menu"
        :style="{ left: menuPosition.x + 'px', top: menuPosition.y + 'px' }"
    >
      <ul>
        <li @click.stop="copyNode">
          <el-icon>
            <CopyDocument/>
          </el-icon>
          复制节点
        </li>
        <li @click.stop="deleteNode">
          <el-icon>
            <Delete/>
          </el-icon>
          删除节点
        </li>
        <li @click.stop="renameNode">
          <el-icon>
            <Edit/>
          </el-icon>
          重命名
        </li>
        <li @click.stop="closeMenu">
          <el-icon>
            <Close/>
          </el-icon>
          取消
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import {ref, computed, onUnmounted, inject} from 'vue';
import {useWorkflowStore} from '@/store/workflow';
import {getNodeTypeConfig} from '@/config/nodeTypes';
import {CopyDocument, Delete, Edit, Close} from '@element-plus/icons-vue';

const props = defineProps({
  node: Object,
  isConnectionHovering: Boolean
});
const emit = defineEmits(['move', 'start-connection', 'show-guide-lines']);
const workflowStore = useWorkflowStore();

const isSelected = computed(() => workflowStore.selectedNodeId === props.node.id);
const nodeTypeConfig = computed(() => getNodeTypeConfig(props.node.type));

const isDragging = ref(false);
const dragOffset = ref({x: 0, y: 0});

const showMenu = ref(false);
const menuPosition = ref({x: 0, y: 0});

// 添加辅助线相关变量
const snapThreshold = 10; // 吸附阈值（像素）
const otherNodes = computed(() => {
  return workflowStore.currentWorkflow?.nodes.filter(n => n.id !== props.node.id) || [];
});

const getPortPosition = (index, totalPorts) => {
  if (totalPorts === 1) return 50;
  const minPosition = 20;
  const maxPosition = 80;
  const range = maxPosition - minPosition;
  const step = range / (totalPorts - 1);
  return minPosition + (step * index);
}

const showContextMenu = (event) => {
  event.preventDefault();
  event.stopPropagation();
  selectNode();
  menuPosition.value = {x: event.offsetX, y: event.offsetY};
  showMenu.value = true;
  setTimeout(() => {
    document.addEventListener('mousedown', closeMenuOnClickOutside);
  }, 0);
}

const closeMenuOnClickOutside = (event) => {
  if (!showMenu.value) return;
  const nodeEl = event.target.closest('.workflow-node');
  if (!nodeEl || nodeEl.getAttribute('data-node-id') !== props.node.id) {
    closeMenu();
  }
}

const closeMenu = () => {
  showMenu.value = false;
  document.removeEventListener('click', closeMenuOnClickOutside);
}

const copyNode = () => {
  workflowStore.duplicateNode(props.node.id, {
    x: props.node.position.x + 20,
    y: props.node.position.y + 20
  });
  closeMenu();
}

const deleteNode = () => {
  workflowStore.deleteNode(props.node.id);
  closeMenu();
}

const renameNode = () => {
  const newName = prompt('请输入新的节点名称:', props.node.label);
  if (newName?.trim()) {
    workflowStore.updateNodeLabel(props.node.id, newName.trim());
  }
  closeMenu();
}

const selectNode = () => {
  workflowStore.selectNode(props.node.id);
  workflowStore.highlightNodeConnections(props.node.id);
}

const startDrag = (event) => {
  if (event.button !== 0) return;
  if (event.target.closest('.port-point')) return;
  isDragging.value = true;
  const rect = event.currentTarget.getBoundingClientRect();
  dragOffset.value = {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top
  };
  document.addEventListener('mousemove', handleDrag);
  document.addEventListener('mouseup', stopDrag);
  selectNode();
}

const handleDrag = (event) => {
  if (!isDragging.value) return;
  event.preventDefault();

  // 计算新位置
  const newX = props.node.position.x + event.movementX;
  const newY = props.node.position.y + event.movementY;

  // 检查是否需要显示辅助线并进行吸附
  const {snappedX, snappedY, guideLines} = calculateGuideLines(newX, newY);

  // 发送辅助线信息到父组件
  emit('show-guide-lines', guideLines);

  // 使用可能吸附后的位置
  emit('move', props.node.id, snappedX, snappedY);
}

const stopDrag = () => {
  if (!isDragging.value) return;
  isDragging.value = false;
  document.removeEventListener('mousemove', handleDrag);
  document.removeEventListener('mouseup', stopDrag);

  // 清除辅助线
  emit('show-guide-lines', []);
}

// 计算辅助线和吸附位置
const calculateGuideLines = (newX, newY) => {
  // 当前节点的中心点和边缘
  const nodeWidth = 200; // 节点宽度
  const nodeHeight = 100; // 估计的节点高度
  const centerX = newX + nodeWidth / 2;
  const centerY = newY + nodeHeight / 2;
  const rightEdge = newX + nodeWidth;
  const bottomEdge = newY + nodeHeight;

  // 初始化结果
  let snappedX = newX;
  let snappedY = newY;
  const guideLines = [];

  // 水平对齐检查
  let minHorizontalDiff = snapThreshold;
  let horizontalGuideLine = null;

  // 垂直对齐检查
  let minVerticalDiff = snapThreshold;
  let verticalGuideLine = null;

  // 遍历其他节点检查对齐
  otherNodes.value.forEach(otherNode => {
    const otherCenterX = otherNode.position.x + nodeWidth / 2;
    const otherCenterY = otherNode.position.y + nodeHeight / 2;
    const otherRightEdge = otherNode.position.x + nodeWidth;
    const otherBottomEdge = otherNode.position.y + nodeHeight;

    // 检查中心点水平对齐
    const centerXDiff = Math.abs(centerX - otherCenterX);
    if (centerXDiff < minHorizontalDiff) {
      minHorizontalDiff = centerXDiff;
      snappedX = otherCenterX - nodeWidth / 2;
      horizontalGuideLine = {
        x1: otherCenterX,
        y1: Math.min(newY, otherNode.position.y) - 20,
        x2: otherCenterX,
        y2: Math.max(bottomEdge, otherBottomEdge) + 20,
        type: 'vertical'
      };
    }

    // 检查左边缘对齐
    const leftEdgeDiff = Math.abs(newX - otherNode.position.x);
    if (leftEdgeDiff < minHorizontalDiff) {
      minHorizontalDiff = leftEdgeDiff;
      snappedX = otherNode.position.x;
      horizontalGuideLine = {
        x1: otherNode.position.x,
        y1: Math.min(newY, otherNode.position.y) - 20,
        x2: otherNode.position.x,
        y2: Math.max(bottomEdge, otherBottomEdge) + 20,
        type: 'vertical'
      };
    }

    // 检查右边缘对齐
    const rightEdgeDiff = Math.abs(rightEdge - otherRightEdge);
    if (rightEdgeDiff < minHorizontalDiff) {
      minHorizontalDiff = rightEdgeDiff;
      snappedX = otherRightEdge - nodeWidth;
      horizontalGuideLine = {
        x1: otherRightEdge,
        y1: Math.min(newY, otherNode.position.y) - 20,
        x2: otherRightEdge,
        y2: Math.max(bottomEdge, otherBottomEdge) + 20,
        type: 'vertical'
      };
    }

    // 检查中心点垂直对齐
    const centerYDiff = Math.abs(centerY - otherCenterY);
    if (centerYDiff < minVerticalDiff) {
      minVerticalDiff = centerYDiff;
      snappedY = otherCenterY - nodeHeight / 2;
      verticalGuideLine = {
        x1: Math.min(newX, otherNode.position.x) - 20,
        y1: otherCenterY,
        x2: Math.max(rightEdge, otherRightEdge) + 20,
        y2: otherCenterY,
        type: 'horizontal'
      };
    }

    // 检查上边缘对齐
    const topEdgeDiff = Math.abs(newY - otherNode.position.y);
    if (topEdgeDiff < minVerticalDiff) {
      minVerticalDiff = topEdgeDiff;
      snappedY = otherNode.position.y;
      verticalGuideLine = {
        x1: Math.min(newX, otherNode.position.x) - 20,
        y1: otherNode.position.y,
        x2: Math.max(rightEdge, otherRightEdge) + 20,
        y2: otherNode.position.y,
        type: 'horizontal'
      };
    }

    // 检查下边缘对齐
    const bottomEdgeDiff = Math.abs(bottomEdge - otherBottomEdge);
    if (bottomEdgeDiff < minVerticalDiff) {
      minVerticalDiff = bottomEdgeDiff;
      snappedY = otherBottomEdge - nodeHeight;
      verticalGuideLine = {
        x1: Math.min(newX, otherNode.position.x) - 20,
        y1: otherBottomEdge,
        x2: Math.max(rightEdge, otherRightEdge) + 20,
        y2: otherBottomEdge,
        type: 'horizontal'
      };
    }
  });

  // 添加辅助线
  if (minHorizontalDiff < snapThreshold && horizontalGuideLine) {
    guideLines.push(horizontalGuideLine);
  }

  if (minVerticalDiff < snapThreshold && verticalGuideLine) {
    guideLines.push(verticalGuideLine);
  }

  return {snappedX, snappedY, guideLines};
}

const startConnection = (portId, isInput, event) => {
  emit('start-connection', props.node.id, portId, isInput, event);
}

onUnmounted(() => {
  document.removeEventListener('click', closeMenuOnClickOutside);
  document.removeEventListener('mousemove', handleDrag);
  document.removeEventListener('mouseup', stopDrag);
});
</script>

<style scoped lang="scss">
.workflow-node {
  position: absolute;
  width: 200px;
  background-color: #fff;
  border: 2px solid #409EFF;
  border-radius: 10px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  user-select: none;
  z-index: 10;
  .selected {
    border-width: 3px;
    box-shadow: 0 0 0 4px rgba(64, 158, 255, 0.3), 0 6px 18px rgba(0, 0, 0, 0.2);
    z-index: 20;
  }
  &:hover {
    box-shadow: 0 0 0 4px rgba(64, 158, 255, 0.3), 0 6px 18px rgba(0, 0, 0, 0.2);
    cursor: default;
  }

  .connection-hover {
    box-shadow: 0 0 0 3px rgba(103, 194, 58, 0.3);
  }

  .node-header {
    display: flex;
    align-items: center;
    padding: 10px 12px;
    color: white;
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
    background-size: 100% 100%;
    gap: 8px;
  }
}

.node-icon {
  width: 16px;
  height: 16px;
  font-size: 16px;
}

.node-label {
  flex: 1;
  font-weight: bold;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.node-content {
  background-color: #f9f9f9;
  border-top: 1px solid #ebeef5;
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  padding: 12px;
  min-height: 60px;
}

.node-description {
  font-size: 13px;
  color: #666;
}

.anchor-points {
  position: absolute;
  height: 100%;
  z-index: 10;
  top: 0;
}

.left-anchors {
  left: -8px;
}

.right-anchors {
  right: -8px;
}

/* 删除或修改这段代码 */
.workflow-node.selected .left-anchors {
  left: -8px;
}

.workflow-node.selected .right-anchors {
  right: -8px;
}


.anchor-point {
  position: absolute;
  width: 16px;
  height: 16px;
  transform: translateY(-120%) translateX(-100%);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: crosshair;
}

.anchor-dot {
  width: 10px;
  height: 10px;
  background-color: #fff;
  border: 2px solid #409EFF;
  border-radius: 50%;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  position: relative;
}

.anchor-dot::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 4px;
  height: 4px;
  background-color: #409EFF;
  border-radius: 50%;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.anchor-point:hover .anchor-dot {
  transform: scale(1.3);
  border-color: #66b1ff;
  box-shadow: 0 0 0 4px rgba(64, 158, 255, 0.2);
}

.anchor-point:hover .anchor-dot::after {
  opacity: 1;
}

.anchor-tooltip {
  position: absolute;
  background-color: #303133;
  color: white;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(0);
  transition: all 0.3s ease;
  pointer-events: none;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.left-anchors .anchor-tooltip {
  left: 24px;
}

.right-anchors .anchor-tooltip {
  right: 24px;
}

.anchor-point:hover .anchor-tooltip {
  opacity: 1;
  transform: translateY(-50%);
}

.node-context-menu {
  position: absolute;
  background-color: white;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 9999;
  min-width: 120px;
}

.node-context-menu ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.node-context-menu li {
  padding: 8px 16px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
}

.node-context-menu li:hover {
  background-color: #f5f7fa;
}

.node-context-menu li:not(:last-child) {
  border-bottom: 1px solid #ebeef5;
}
</style>
